using System;
using System.Text;
using System.Threading;
using LocalOverride.Fiddler;
using LocalOverride.Fiddler.UI;
using NUnit.Framework;
using NSubstitute;

namespace LocalOverride.Tests.UI
{
    [TestFixture]
    public class MappingEditorPresenterLoggingTests
    {
        private const string NewLine = "\r\n";
        private ILoggingView view;
        private Logger logger;

        [Test]
        public void ViewIsUpdatedWithLogMessages()
        {
            InitializePresenter();

            const string message = "Test Message";
            logger.Log(message);

            view.Received().LogMessages = message + NewLine;
        }

        [Test]
        public void LogMessagesAreAppenededToTheView()
        {
            InitializePresenter();

            const string message = "Test Message";
            logger.Log(message);
            logger.Log(message);

            const string expectedMessage = message + NewLine + message + NewLine;

            view.Received().LogMessages = expectedMessage;
        }

        [Test]
        public void OldMessagesAreRemovedOnceLineLimitIsReached()
        {
            InitializePresenter();

            const string message = "Test Message";
            logger.Log(message);

            var expectedMessage = new StringBuilder();
            for (int i = 0; i < MappingEditorPresenter.MaxLogLines; i++)
            {
                var currentMessage = message + i;
                expectedMessage.AppendLine(currentMessage);
                logger.Log(currentMessage);
            }

            view.Received().LogMessages = expectedMessage.ToString();
        }

        // This is looking for a race condition. Need to think about how I prove this?
        [Test]
        public void IsThreadSafe()
        {
            InitializePresenter();

            int count = 0;
            view.WhenForAnyArgs(x => x.LogMessages = null).Do(x => count++);

            var firstThread = new Thread(LogMessage);
            var secondThread = new Thread(LogMessage);
            var thirdThread = new Thread(LogMessage);
            firstThread.Start();
            secondThread.Start();
            thirdThread.Start();

            firstThread.Join();
            secondThread.Join();
            thirdThread.Join();

            Assert.AreEqual(1000*3, count);
        }

        private void LogMessage()
        {
            for (int i = 0; i < 1000; i++)
            {
                logger.Log("test message");
            }
        }

        private void InitializePresenter()
        {
            view = Substitute.For<ILoggingView>();
            
            logger = new Logger();

            new LoggingPresenter(view, logger);
        }
    }
}